/*
 * @Author: lujin49
 * @Date: 2024-12-03 14:07:32
 * @LastEditTime: 2024-12-24 12:39:50
 * @Description:
 */
package main

import (
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"net/url"
	"os"
	"path/filepath"
	"sync"
	"time"

	"deerApi/checkicon"
	"deerApi/util"

	"github.com/gin-gonic/gin"
)

type LoginAttempt struct {
	FailCount  int
	LastFailed time.Time
}

// 使用 IP 地址作为 key 来记录登录尝试
var loginAttempts = make(map[string]*LoginAttempt)
var loginMutex sync.Mutex

// 添加用户结构体
type User struct {
	Username string `json:"username"`
	Password string `json:"password"`
	BookFile string `json:"bookfile"`
}

type UserConfig struct {
	Users []User `json:"users"`
}

// 添加全局变量
var userConfig UserConfig

// 在 main() 函数开始处添加配置加载
func init() {
	// 读取用户配置文件
	data, err := os.ReadFile("user.json")
	if err != nil {
		panic("无法读取用户配置文件: " + err.Error())
	}

	err = json.Unmarshal(data, &userConfig)
	if err != nil {
		panic("解析用户配置文件失败: " + err.Error())
	}
}

// 添加用户验证函数
func validateUser(username, password string) (User, bool) {
	for _, user := range userConfig.Users {
		if user.Username == username && user.Password == password {
			return user, true
		}
	}
	return User{}, false
}

func WriteFile(bookmarks string, filename string) string {
	// 将数据写入文件, 覆盖原有数据
	err := os.WriteFile(filename, []byte(bookmarks), 0644)
	if err != nil {
		return err.Error()
	}
	return ""
}

func GetFaviconUrl(urlstr string) string {
	parsedURL, err := url.Parse(urlstr)
	if err != nil {
		fmt.Println("Error parsing URL:", err)
		return ""
	}
	// 获取 Scheme 和 Host
	return parsedURL.Scheme + "://" + parsedURL.Host
}

// 在 User 结构体后添加注册请求结构体
type RegisterRequest struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

func main() {
	// 创建一个默认的路由引擎
	r := gin.Default()

	r.Use(func(c *gin.Context) {
		c.Writer.Header().Set("Access-Control-Allow-Origin", "*")
		c.Writer.Header().Set("Access-Control-Allow-Credentials", "true")
		c.Writer.Header().Set("Access-Control-Allow-Headers", "Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization, accept, origin, Cache-Control, X-Requested-With")
		c.Writer.Header().Set("Access-Control-Allow-Methods", "POST, OPTIONS, GET, PUT")

		if c.Request.Method == "OPTIONS" {
			c.AbortWithStatus(204)
			return
		}

		c.Next()
	})

	r.Static("/css", "./css")
	r.StaticFile("/js/books.js", "./js/books.js")
	r.StaticFile("/favicon.ico", "./favicon.ico")
	r.StaticFile("/icon.jpg", "./icon.jpg")

	// 定义一个 GET 请求的路由处理函数
	r.GET("/", func(c *gin.Context) {
		c.File("index.html")
	})

	//登录账号
	r.GET("/login", func(c *gin.Context) {
		// 获取客户端 IP 地址
		clientIP := c.ClientIP()

		// 检查 IP 是否被锁定
		loginMutex.Lock()
		attempt, exists := loginAttempts[clientIP]
		if exists {
			// 如果距离上次失败超过24小时，重置计数
			if time.Since(attempt.LastFailed) > 24*time.Hour {
				attempt.FailCount = 0
			} else if attempt.FailCount >= 5 {
				loginMutex.Unlock()
				c.JSON(http.StatusOK, gin.H{
					"code":    403,
					"message": "登录尝试次数过多，请24小时后再试",
				})
				return
			}
		}
		loginMutex.Unlock()

		//获取get参数
		username := c.Query("username")
		password := c.Query("password")
		flag := c.Query("flag") //标志,如果不存在或是为0,则正常返回书签数据,如果为1,则表示是 只登录,不返回书签数据

		// 验证用户
		if user, valid := validateUser(username, password); valid {
			// 登录成功，重置该 IP 的失败计数
			loginMutex.Lock()
			delete(loginAttempts, clientIP)
			loginMutex.Unlock()

			// 读取对应用户的书签文件
			data, err := os.ReadFile(user.BookFile)
			if err != nil {
				// 如果文件不存在，创建空文件
				if os.IsNotExist(err) {
					err = os.WriteFile(user.BookFile, []byte("[]"), 0644)
					if err != nil {
						c.JSON(http.StatusOK, gin.H{"code": 220, "message": "创建书签文件失败"})
						return
					}
					data = []byte("[]")
				} else {
					c.JSON(http.StatusOK, gin.H{"code": 220, "message": "读取书签数据失败"})
					return
				}
			}
			//根据flag判断是否返回数据
			if flag == "1" {
				c.JSON(http.StatusOK, gin.H{
					"code":    200,
					"message": "登录成功",
				})
			} else {
				c.JSON(http.StatusOK, gin.H{
					"code":    200,
					"message": "登录成功",
					"books":   string(data),
				})
			}
		} else {
			// 更新失败计数
			loginMutex.Lock()
			if !exists {
				loginAttempts[clientIP] = &LoginAttempt{
					FailCount:  1,
					LastFailed: time.Now(),
				}
			} else {
				attempt.FailCount++
				attempt.LastFailed = time.Now()
			}
			failCount := loginAttempts[clientIP].FailCount
			loginMutex.Unlock()

			message := fmt.Sprintf("账号或密码错误，还剩 %d 次尝试机会", 5-failCount)
			if failCount >= 5 {
				message = "登录尝试次数过多，请24小时后再试"
			}

			c.JSON(http.StatusOK, gin.H{
				"code":    104,
				"message": message,
			})
		}
	})
	//创建一个POST请求的路由处理函数
	r.POST("/send", func(c *gin.Context) {
		// username := c.Query("username") // 添加用户名参数
		// 通过请求头中的 authorization 字段获取用户名
		Authorstr := c.GetHeader("Authorization")
		// 将 Authorization 字段的值解析为用户名和密码 (格式为 "Basic base64(username:password)")
		username, password, err := util.DecodeBasicAuth(Authorstr)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": "用户名或密码无效"})
			return
		}
		// 验证用户
		if _, valid := validateUser(username, password); !valid {
			//\如果用户名或密码无效，返回错误响应
			c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码无效"})
			return
		}

		// 查找用户对应的书签文件
		var bookFile string
		for _, user := range userConfig.Users {
			if user.Username == username {
				bookFile = user.BookFile
				break
			}
		}

		if bookFile == "" {
			c.JSON(http.StatusBadRequest, gin.H{"error": "用户未找到"})
			return
		}

		bodystr, err := io.ReadAll(c.Request.Body)
		if err != nil {
			c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
			return
		}

		// 将数据写入对应用户的文件
		go checkicon.ReadBooks(bodystr, bookFile)
		c.JSON(http.StatusOK, gin.H{"message": "JSON received successfully"})
	})

	// 添加注册页面路由
	r.StaticFile("/register.html", "./register.html")

	// 添加注册接口
	r.POST("/register", func(c *gin.Context) {
		var req RegisterRequest
		if err := c.BindJSON(&req); err != nil {
			c.JSON(http.StatusBadRequest, gin.H{
				"code":    400,
				"message": "无效的请求数据",
			})
			return
		}

		// 验证用户名长度
		if len(req.Username) < 3 || len(req.Username) > 20 {
			c.JSON(http.StatusOK, gin.H{
				"code":    400,
				"message": "用户名长度必须在3-20个字符之间",
			})
			return
		}

		// 验证密码长度
		if len(req.Password) < 6 || len(req.Password) > 20 {
			c.JSON(http.StatusOK, gin.H{
				"code":    400,
				"message": "密码长度必须在6-20个字符之间",
			})
			return
		}

		// 检查用户名是否已存在
		for _, user := range userConfig.Users {
			if user.Username == req.Username {
				c.JSON(http.StatusOK, gin.H{
					"code":    400,
					"message": "用户名已存在",
				})
				return
			}
		}

		// 创建新用户的书签文件
		bookFile := filepath.Join("js", req.Username+".json")
		err := os.WriteFile(bookFile, []byte("[]"), 0644)
		if err != nil {
			c.JSON(http.StatusOK, gin.H{
				"code":    500,
				"message": "创建用户书签文件失败",
			})
			return
		}

		// 添加新用户
		newUser := User{
			Username: req.Username,
			Password: req.Password,
			BookFile: bookFile,
		}
		userConfig.Users = append(userConfig.Users, newUser)

		// 保存更新后的用户配置
		userConfigJSON, err := json.MarshalIndent(userConfig, "", "    ")
		if err != nil {
			c.JSON(http.StatusOK, gin.H{
				"code":    500,
				"message": "保存用户配置失败",
			})
			return
		}

		err = os.WriteFile("user.json", userConfigJSON, 0644)
		if err != nil {
			c.JSON(http.StatusOK, gin.H{
				"code":    500,
				"message": "保存用户配置失败",
			})
			return
		}

		c.JSON(http.StatusOK, gin.H{
			"code":    200,
			"message": "注册成功",
		})
	})

	// 启动 HTTP 服务器，监听在 8080 端口
	r.Run(":8080")
}
